import OSS from 'ali-oss'
import { OSS_CONFIG, generateFileName, validateFileType, validateFileSize } from './ossConfig'

// 上传进度回调类型
export type UploadProgressCallback = (status: UploadStatus) => void

// 上传结果类型
export interface UploadResult {
  success: boolean
  url?: string
  error?: string
  fileName?: string
  uploadId?: string // 分片上传ID，用于断点续传
  fileSize?: number // 文件大小
  uploadTime?: number // 上传耗时
}

// 上传状态类型
export interface UploadStatus {
  isUploading: boolean
  progress: number
  uploadedBytes: number
  totalBytes: number
  speed: number // 上传速度 (bytes/s)
  remainingTime: number // 剩余时间 (秒)
  error?: string
}

// 创建OSS客户端
const createOSSClient = (): OSS => {
  return new OSS({
    region: OSS_CONFIG.region,
    accessKeyId: OSS_CONFIG.accessKeyId,
    accessKeySecret: OSS_CONFIG.accessKeySecret,
    bucket: OSS_CONFIG.bucket,
    // 启用分片上传
    multipart: true,
    // 分片上传阈值
    multipartThreshold: OSS_CONFIG.multipartThreshold,
    // 分片大小
    partSize: OSS_CONFIG.partSize,
  })
}

// 计算上传速度和剩余时间
const calculateSpeedAndTime = (
  uploadedBytes: number,
  totalBytes: number,
  startTime: number
): { speed: number; remainingTime: number } => {
  const elapsed = (Date.now() - startTime) / 1000 // 秒
  const speed = uploadedBytes / elapsed // bytes/s
  const remainingBytes = totalBytes - uploadedBytes
  const remainingTime = remainingBytes / speed // 秒
  
  return {
    speed: isFinite(speed) ? speed : 0,
    remainingTime: isFinite(remainingTime) ? remainingTime : 0
  }
}

// 单文件上传
export const uploadSingleFile = async (
  file: File,
  onProgress?: UploadProgressCallback
): Promise<UploadResult> => {
  const startTime = Date.now()
  
  try {
    // 验证文件类型
    if (!validateFileType(file)) {
      return {
        success: false,
        error: '不支持的文件类型，请上传图片文件',
        fileSize: file.size
      }
    }

    // 验证文件大小
    if (!validateFileSize(file)) {
      return {
        success: false,
        error: `文件大小不能超过 ${OSS_CONFIG.maxFileSize / 1024 / 1024}MB`,
        fileSize: file.size
      }
    }

    const client = createOSSClient()
    const fileName = generateFileName(file.name)
    const objectKey = `${OSS_CONFIG.uploadPath}${fileName}`

    // 根据文件大小选择上传方式和配置
    if (file.size > OSS_CONFIG.multipartThreshold) {
      // 大文件使用分片上传
      return await uploadLargeFile(client, file, objectKey, onProgress, startTime)
    } else {
      // 小文件使用普通上传
      return await uploadSmallFile(client, file, objectKey, onProgress, startTime)
    }
  } catch (error) {
    console.error('上传失败:', error)
    return {
      success: false,
      error: error instanceof Error ? error.message : '上传失败',
      fileSize: file.size,
      uploadTime: Date.now() - startTime
    }
  }
}

// 小文件上传
const uploadSmallFile = async (
  client: OSS,
  file: File,
  objectKey: string,
  onProgress?: UploadProgressCallback,
  startTime: number = Date.now()
): Promise<UploadResult> => {
  try {
    const result = await client.put(objectKey, file, {
      progress: (p: number) => {
        if (onProgress) {
          const uploadedBytes = Math.round(p * file.size)
          const { speed, remainingTime } = calculateSpeedAndTime(uploadedBytes, file.size, startTime)
          
          onProgress({
            isUploading: true,
            progress: Math.round(p * 100),
            uploadedBytes,
            totalBytes: file.size,
            speed,
            remainingTime
          })
        }
      }
    })

    return {
      success: true,
      url: result.url,
      fileName: objectKey,
      fileSize: file.size,
      uploadTime: Date.now() - startTime
    }
  } catch (error) {
    throw new Error(`小文件上传失败: ${error}`)
  }
}

// 大文件分片上传
const uploadLargeFile = async (
  client: OSS,
  file: File,
  objectKey: string,
  onProgress?: UploadProgressCallback,
  startTime: number = Date.now()
): Promise<UploadResult> => {
  try {
    // 根据文件大小选择不同的分片配置
    const isSuperLarge = file.size > OSS_CONFIG.largeFileConfig.superLargeThreshold
    const partSize = isSuperLarge ? OSS_CONFIG.largeFileConfig.superLargePartSize : OSS_CONFIG.partSize
    const parallel = isSuperLarge ? OSS_CONFIG.largeFileConfig.superLargeParallel : OSS_CONFIG.parallel

    console.log(`开始分片上传: ${file.name}, 大小: ${(file.size / 1024 / 1024).toFixed(2)}MB, 分片大小: ${(partSize / 1024 / 1024).toFixed(2)}MB`)

    // 开始分片上传
    const result = await client.multipartUpload(objectKey, file, {
      progress: (p: number) => {
        if (onProgress) {
          const uploadedBytes = Math.round(p * file.size)
          const { speed, remainingTime } = calculateSpeedAndTime(uploadedBytes, file.size, startTime)
          
          onProgress({
            isUploading: true,
            progress: Math.round(p * 100),
            uploadedBytes,
            totalBytes: file.size,
            speed,
            remainingTime
          })
        }
      },
      // 分片大小
      partSize,
      // 并发上传的分片数
      parallel,
      // 重试次数
      retries: OSS_CONFIG.retries,
    })

    return {
      success: true,
      url: result.res.requestUrls[0].split('?')[0], // 获取不带参数的URL
      fileName: objectKey,
      uploadId: `upload_${Date.now()}`,
      fileSize: file.size,
      uploadTime: Date.now() - startTime
    }
  } catch (error) {
    console.error('大文件上传失败:', error)
    throw new Error(`大文件上传失败: ${error}`)
  }
}

// 批量上传文件
export const uploadMultipleFiles = async (
  files: File[],
  onProgress?: (fileIndex: number, status: UploadStatus) => void
): Promise<UploadResult[]> => {
  const results: UploadResult[] = []
  
  for (let i = 0; i < files.length; i++) {
    const file = files[i]
    const result = await uploadSingleFile(file, (status) => {
      if (onProgress) {
        onProgress(i, status)
      }
    })
    results.push(result)
  }
  
  return results
}

// 取消上传（用于分片上传）
export const cancelUpload = async (objectKey: string, uploadId?: string): Promise<boolean> => {
  try {
    const client = createOSSClient()
    if (uploadId) {
      await client.abortMultipartUpload(objectKey, uploadId)
    } else {
      // 如果没有uploadId，尝试取消所有未完成的分片上传
      await client.abortMultipartUpload(objectKey)
    }
    return true
  } catch (error) {
    console.error('取消上传失败:', error)
    return false
  }
}

// 上传控制器类，用于管理上传状态和取消操作
export class UploadController {
  private uploadId?: string
  private objectKey?: string
  private isCancelled = false

  constructor(objectKey: string, uploadId?: string) {
    this.objectKey = objectKey
    this.uploadId = uploadId
  }

  async cancel(): Promise<boolean> {
    this.isCancelled = true
    if (this.objectKey) {
      return await cancelUpload(this.objectKey, this.uploadId)
    }
    return false
  }

  get isCancelledState(): boolean {
    return this.isCancelled
  }

  setUploadId(uploadId: string): void {
    this.uploadId = uploadId
  }
}

// 获取文件URL（带签名，用于私有文件访问）
export const getSignedUrl = (objectKey: string, expires: number = 3600): string => {
  const client = createOSSClient()
  return client.signatureUrl(objectKey, { expires })
}

// 删除文件
export const deleteFile = async (objectKey: string): Promise<boolean> => {
  try {
    const client = createOSSClient()
    await client.delete(objectKey)
    return true
  } catch (error) {
    console.error('删除文件失败:', error)
    return false
  }
}

